package com.nacos.demo;

import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;

import java.util.Properties;
import java.util.concurrent.Executor;

/**
 * nacos配置管理
 *
 * @author 夜曲sin
 * @create 2021/6/22
 */
public class NacosConfigDemo {

    // nacos服务器地址及端口
    public static final String serverAddr = "http://47.99.169.53:8848";
    // 超时时间
    public static final long timeoutMs = 5000;


    public static void main(String[] args) throws Exception {
    /*
        《nacos配置管理相关笔记》
        【测试版本】nacos2.0.2
        【注   意】远程服务器必须同时开放8848和9848端口，否则将获取失败！

        1、Nacos服务启动时需要添加参数-m standalone，否则将启动失败！
            sh startup.sh -m standalone     // 单个服务器部署nacos
            sh startup.sh -m cluster        // 集群部署nacos
        2、配置的导入/导出/克隆
            常见场景：dev环境测试完成后，通常会再部署到test环境或者prod环境中，此时在dev环境命名空间下，选中并导出所需配置，
          然后在test/prod环境导入即可快速部署到其它环境，修改部分配置即可，以此节省部署新环境时间。
            新版本还可以使用克隆配置的功能！
        3、历史版本
            历史版本功能中，可以查询指定配置的历史修改记录（保留最近30天）
        4、配置变化监听
            客户端可以监听指定配置的变化，并且在变化时获取到最新的配置。
            在Nacos的管理界面[监听查询]中可以查看指定配置当前在监听的客户端。
        5、nacos用户登录密码使用BCrypt加密
            该加密工具位于org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder中。
        6、nacos集群部署
            - 3个及以上Nacos才能构成集群
            - 修改conf目录下文件名cluster.conf.example -> cluster.conf，并在文件中添加集群的机器IP和端口，如：
                192.168.16.101:8848
                192.168.16.102:8848
                192.168.16.103:8848
              此配置是为了使nacos各机器之间互相发现。
            - 如果是单机演示，需要修改端口号，防止端口冲突；
                如果服务器有多个IP，需要指定具体的IP地址，如：nacos.inetutils.ip-address=127.0.0.1
            - nacos客户端在server-addr中同时配置多个nacos服务器地址，如：
                spring:
                  cloud:
                    nacos:
                      config:
                        server-addr: 47.99.169.53:8848,47.99.169.54:8848,47.99.169.55:8848
               使用集群后，nacos集群会自动选举出Leader，其它机器为Follower，当Leader宕机时，将自动选举出新的Leader
            - 生产环境推荐通过域名+VIP模式的方式来实现nacos集群。这样当nacos集群迁移时，客户端配置无需修改。

     */

        // 测试1：获取远程nacos服务上的配置信息（默认命名空间）
//        test1_getConfig_defaultNameSpace();

        // 测试2：获取远程nacos服务上的配置信息（指定命名空间）
        test2_getConfig_specifiedNameSpace();

        // 测试3：客户端监听指定配置变化
//        test2_listenConfigChange();
    }

    /**
     * 获取远程nacos服务上的配置信息（默认命名空间）
     */
    public static void test1_getConfig_defaultNameSpace() throws NacosException {
        String dataId = "nacos-simple-demo.yaml"; // 配置id
        String group = "DEFAULT_GROUP"; // 配置组
        long timeoutMs = 5000; // 超时时间
        // 如果不指定namespace，默认获取public命名空间里的配置
        ConfigService configService = NacosFactory.createConfigService(serverAddr);
        String config = configService.getConfig(dataId, group, timeoutMs);

        System.out.println(config);
    }

    /**
     * 获取远程nacos服务上的配置信息（指定命名空间）
     */
    public static void test2_getConfig_specifiedNameSpace() throws NacosException {
        String dataId = "nacos-simple-demo.yaml"; // 配置id
        String group = "DEFAULT_GROUP"; // 配置组
        String namespace = "68656778-db16-44c9-a665-710dfc29963e"; // 命名空间ID，注意不是名称！

        // 指定namespace
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
        properties.put(PropertyKeyConst.NAMESPACE, namespace);

        ConfigService configService = NacosFactory.createConfigService(properties);
        String config = configService.getConfig(dataId, group, timeoutMs);

        System.out.println(config);
    }

    /**
     * 客户端监听指定配置变化
     */
    public static void test2_listenConfigChange() throws NacosException, InterruptedException {
        String dataId = "nacos-simple-demo.yaml"; // 配置id
        String group = "DEFAULT_GROUP"; // 配置组
        String namespace = "68656778-db16-44c9-a665-710dfc29963e"; // 命名空间ID，注意不是名称！

        // 指定namespace
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
        properties.put(PropertyKeyConst.NAMESPACE, namespace);

        ConfigService configService = NacosFactory.createConfigService(properties);
        configService.addListener(dataId, group, new Listener() {
            @Override
            public Executor getExecutor() {
                return null;
            }
            /**
             * 当配置变化时，获取到的配置信息
             *
             * @param configInfo
             */
            @Override
            public void receiveConfigInfo(String configInfo) {
                System.out.println("配置发生变化：\n" + configInfo);
            }
        });
        // 使主线程不退出
        Thread.sleep(300000);
    }

}
